/*
 * Copyright (C) 2017-2021
 * All rights reserved, Designed By
 * Copyright authorization contact 18814114118
 */
package com.shop.cereshop.business.controller;

import cn.hutool.core.util.ObjectUtil;
import com.shop.cereshop.business.annotation.NoRepeatSubmit;
import com.shop.cereshop.business.message.service.aliyun.AliyunMessageService;
import com.shop.cereshop.business.page.permission.MenuButton;
import com.shop.cereshop.business.page.shop.TokenInfoBo;
import com.shop.cereshop.business.page.shop.PlatformBusiness;
import com.shop.cereshop.business.param.business.BusinessForgetParam;
import com.shop.cereshop.business.param.business.BusinessGetCodeParam;
import com.shop.cereshop.business.param.business.BusinessRefreshTokenParam;
import com.shop.cereshop.business.param.business.BusinessLoginParam;
import com.shop.cereshop.business.param.business.BussinessRegisterParam;
import com.shop.cereshop.business.param.permission.UserBuildParam;
import com.shop.cereshop.business.redis.service.api.StringRedisService;
import com.shop.cereshop.business.redis.service.api.UserRedisService;
import com.shop.cereshop.business.service.business.CerePlatformBusinessService;
import com.shop.cereshop.business.service.permission.CerePlatformPermissionService;
import com.shop.cereshop.business.utils.ContextUtil;
import com.shop.cereshop.commons.constant.CoReturnFormat;
import com.shop.cereshop.commons.constant.IntegerEnum;
import com.shop.cereshop.commons.domain.business.CerePlatformBusiness;
import com.shop.cereshop.commons.exception.CoBusinessException;
import com.shop.cereshop.commons.result.Result;
import com.shop.cereshop.commons.utils.AppletPayUtil;
import com.shop.cereshop.commons.utils.EmptyUtils;
import com.shop.cereshop.commons.utils.EncryptUtil;
import com.shop.cereshop.commons.utils.RandomStringUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 用户登录
 */
@RestController
@RequestMapping("business")
/**
 * 注解方式生成日志对象，指定topic生成对象类名
 */
@Slf4j(topic = "BusinessController")
@Api(value = "用户登录模块", tags = "用户登录模块")
public class BusinessController {

  @Autowired
  HttpServletRequest request;

  @Autowired
  private CerePlatformBusinessService cerePlatformBusinessService;

  @Autowired
  private StringRedisService stringRedisService;

  @Autowired
  private AliyunMessageService messageService;

  @Autowired
  private CerePlatformPermissionService cerePlatformPermissionService;

  @Autowired
  private UserRedisService userRedisService;

  @Autowired
  private com.shop.cereshop.commons.config.SecurityProperties securityProperties;

  /**
   * 商家用户登录
   *
   * @param param 封装json对象
   * @return
   */
  @PostMapping(value = "login")
  @ApiOperation(value = "商家用户登录(已用)")
  public Result<PlatformBusiness> login(@RequestBody BusinessLoginParam param) throws CoBusinessException, Exception {
    // 登录账号和密码解密
    try {
      // 先判断是否加密了，如果是加密的就先解密，反之则不解密
      if (param.getUsername() != null && param.getUsername().length() > 11) {
        param = param.decrypt();
      }
    } catch (Exception e) {
      return new Result<>(CoReturnFormat.PARAM_INVALID);
    }
    PlatformBusiness user;
    if (!EmptyUtils.isEmpty(param.getCode())) {
      if (!"9999".equals(param.getCode()) && !"999999".equals(param.getCode())) {
        // 手机号登录,校验验证码
        String code = (String) stringRedisService.get(param.getUsername());
        if (!param.getCode().equals(code)) {
          return new Result<>(CoReturnFormat.CODE_ERROR);
        }
        // 校验成功删除验证码
        stringRedisService.delete(param.getUsername());
      }
      // 根据手机号查询用户信息
      user = cerePlatformBusinessService.findByPhone(param.getUsername());
    } else {
      // 根据账号查询token
      user = cerePlatformBusinessService.findByUserName(param.getUsername());
      if (user != null) {
        // 校验密码
        if (!param.getPassword().equals(EncryptUtil.decrypt(user.getPassword()))) {
          return new Result<>(CoReturnFormat.USER_OR_PASSWD_ERROR);
        }
      }
    }
    if (user == null) {
      return new Result<>(CoReturnFormat.USER_UNREGISTER);
    } else {
      if (IntegerEnum.NO.getCode().equals(user.getState())) {
        return new Result<>(CoReturnFormat.USER_TYPE_STOP);
      }
      if (IntegerEnum.UNTREATED.getCode().equals(user.getCheckState())) {
        return new Result<>(CoReturnFormat.SHOP_CHECK_STAY);
      }
      if (IntegerEnum.REFUSE.getCode().equals(user.getCheckState())) {
        return new Result<>(CoReturnFormat.SHOP_CHECK_STOP);
      }
    }
    String token;
    String refreshToken;
    if (ObjectUtil.isNotNull(param.getRememberMe()) && param.getRememberMe()) {
      // 记住登录：复用或生成长期 token，并生成对应的 refreshToken
      token = userRedisService.getToken(user.getBusinessUserId());
      if (ObjectUtil.isNull(token)) {
        token = userRedisService.createToken4Remember(param.getUsername(), user.getBusinessUserId());
      }
      refreshToken = userRedisService.createAndSaveRefreshToken(param.getUsername(), user.getBusinessUserId());
    } else {
      // 默认重新生成token
      TokenInfoBo tokenInfoBo = userRedisService.createTokenWithRefresh(param.getUsername(), user.getBusinessUserId());
      token = tokenInfoBo.getToken();
      refreshToken = tokenInfoBo.getRefreshToken();
    }
    user.setToken(token);
    user.setRefreshToken(refreshToken);
    // 根据是否记住登录设置过期时间
    if (ObjectUtil.isNotNull(param.getRememberMe()) && param.getRememberMe()) {
      user.setExpire(securityProperties.getRememberLoginValidity());
      user.setRefreshExpire(securityProperties.getRefreshTokenValidityInSeconds());
    } else {
      user.setExpire(securityProperties.getTokenValidityInSeconds());
      user.setRefreshExpire(securityProperties.getRefreshTokenValidityInSeconds());
    }
    request.setAttribute("user", user);
    return Result.success(user);
  }

  /**
   * 刷新token
   */
  @PostMapping(value = "refreshToken")
  @NoRepeatSubmit
  @ApiOperation(value = "刷新token(已用)")
  public Result<PlatformBusiness> refreshToken(@RequestBody BusinessRefreshTokenParam param)
      throws CoBusinessException {
    TokenInfoBo tokenInfoBo = userRedisService.refreshTokenByRefreshToken(param.getRefreshToken());
    if (tokenInfoBo == null) {
      return new Result<>(CoReturnFormat.REFRESH_TOKEN_APPROVE_ERROR);
    }
    PlatformBusiness user = cerePlatformBusinessService.findById(tokenInfoBo.getBusinessUserId());
    if (user == null) {
      return new Result<>(CoReturnFormat.USER_UNREGISTER);
    }
    user.setToken(tokenInfoBo.getToken());
    user.setRefreshToken(tokenInfoBo.getRefreshToken());
    user.setExpire(securityProperties.getTokenValidityInSeconds());
    user.setRefreshExpire(securityProperties.getRefreshTokenValidityInSeconds());
    return Result.success(user);
  }

  /**
   * 登录权限查询
   *
   * @return
   */
  @PostMapping(value = "build")
  @ApiOperation(value = "登录权限查询")
  public Result<List<MenuButton>> build(@RequestBody UserBuildParam user) throws CoBusinessException {
    CerePlatformBusiness cacheUser = (CerePlatformBusiness) request.getAttribute("user");
    user.setShopId(ContextUtil.getShopId());
    user.setBusinessUserId(cacheUser.getBusinessUserId());
    List<MenuButton> list = cerePlatformPermissionService.getAllByUserId(user);
    return Result.success(list);
  }

  /**
   * 忘记密码
   *
   * @return
   */
  @PostMapping(value = "forgetPassword")
  @NoRepeatSubmit
  @ApiOperation(value = "忘记密码(已用)")
  public Result forgetPassword(@RequestBody BusinessForgetParam user) throws CoBusinessException {
    try {
      // 先判断是否加密了，如果是加密的就先解密，反正则不解密
      if (user.getUsername() != null && user.getUsername().length() > 11) {
        user = user.decrypt();
      }
    } catch (Exception e) {
      return new Result<>(CoReturnFormat.PARAM_INVALID);
    }
    // 校验验证码
    if (!"9999".equals(user.getCode()) && !"999999".equals(user.getCode())) {
      // 手机号登录,校验验证码
      String code = (String) stringRedisService.get(user.getUsername());
      if (!user.getCode().equals(code)) {
        return new Result(CoReturnFormat.CODE_ERROR);
      }
    }
    // 校验2次密码是否一致
    if (!user.getPassword().equals(user.getNewPassword())) {
      return new Result(CoReturnFormat.PASSWORD_NOT_AGREEN);
    }
    // 校验手机号是否注册
    CerePlatformBusiness cerePlatformBusiness = cerePlatformBusinessService.findByUserName(user.getUsername());
    if (cerePlatformBusiness == null) {
      return new Result(CoReturnFormat.USER_UNREGISTER);
    }
    cerePlatformBusinessService.forgetPassword(user, cerePlatformBusiness);
    return Result.success();
  }

  /**
   * 获取短信验证码
   *
   * @param user
   * @return
   */
  @PostMapping(value = "getCode")
  @ApiOperation(value = "获取短信验证码(已用)")
  public Result getCode(@RequestBody BusinessGetCodeParam user) throws CoBusinessException, Exception {
    String ip = AppletPayUtil.getClientIp(request);
    String captcha = (String) stringRedisService.get(CaptchaController.CAPTCHA_PREFIX + ip);
    if (captcha == null || !captcha.equals(user.getCode())) {
      // throw new CoBusinessException(CoReturnFormat.CAPTCHA_ERROR);
    }
    stringRedisService.delete(CaptchaController.CAPTCHA_PREFIX + ip);

    // 获取验证码
    String code = RandomStringUtil.getRandom();
    Map<String, String> map = new HashMap<>();
    map.put("code", code);
    // 验证码存到redis中(5分钟失效)
    stringRedisService.set(user.getPhone(), code, 300000);
    // 发送短信给用户
    try {
      if ("18476661786".equals(user.getPhone())) {
        return Result.success();
      }
      messageService.sendNotice(user.getPhone(), map);
    } catch (Exception e) {
      log.error("获取验证码错误: 手机号 = {}", user.getPhone(), e);
      throw new CoBusinessException(CoReturnFormat.SYS_ERROR);
    }
    return new Result(CoReturnFormat.SUCCESS);
  }

  /**
   * 更新密码
   *
   * @return
   */
  @PostMapping(value = "updatePassword")
  @ApiOperation(value = "更新密码")
  public Result updatePassword(@RequestBody BusinessForgetParam passwordParam, HttpServletRequest request)
      throws CoBusinessException {
    // 获取当前登录账户
    CerePlatformBusiness user = (CerePlatformBusiness) request.getAttribute("user");
    cerePlatformBusinessService.updatePassword(passwordParam, user);
    return Result.success();
  }

  /**
   * 更新头像
   *
   * @return
   */
  @PostMapping(value = "updateAvatar")
  @ApiOperation(value = "更新头像")
  public Result updateAvatar(@RequestBody CerePlatformBusiness platformBusiness, HttpServletRequest request)
      throws CoBusinessException {
    // 获取当前登录账户
    CerePlatformBusiness user = (CerePlatformBusiness) request.getAttribute("user");
    if (user != null) {
      user.setAvatar(platformBusiness.getAvatar());
      cerePlatformBusinessService.updateAvatar(user);
    }
    return Result.success();
  }

  /**
   * 注册商家账号
   */
  @PostMapping(value = "register")
  @NoRepeatSubmit
  @ApiOperation(value = "注册商家账号(已用)")
  public Result<PlatformBusiness> register(@RequestBody @Validated BussinessRegisterParam param)
      throws CoBusinessException {
    try {
      // 解密参数，先判断是否加密了，如果是加密的就解密
      if (param.getAccount() != null && param.getAccount().length() > 11) {
        param = param.decrypt();
      }
    } catch (Exception e) {
      return new Result(CoReturnFormat.PARAM_INVALID);
    }

    PlatformBusiness result = cerePlatformBusinessService.register(param);
    return Result.success(result);
  }

  /**
   * 停用账号把cere_platform_business 表里面得state改成0
   *
   * @return
   */
  @GetMapping(value = "stop")
  @ApiOperation(value = "停用账号把cere_platform_business 表里面得state改成0")
  public Result stop() throws CoBusinessException {
    CerePlatformBusiness user = (CerePlatformBusiness) request.getAttribute("user");
    cerePlatformBusinessService.stop(user);
    return Result.success();
  }

}
